﻿Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Web
Imports System.Web.Configuration
Imports System.IO
Imports System.Net

Friend Class ThumbHandler
    Implements IHttpHandler

    'Querystring fields.
    'a - image url
    'b - image width
    'c - image height
    'd - image quality
    'e - image background color
    'f - corner type
    'g - corner radius
    'h - top left corner type
    'i - top right corner type
    'j - bottom right corner type
    'k - bottom left corner type
    'l - top left corner radius
    'm - top right corner radius
    'n - bottom right corner radius
    'o - bottom left corner radius
    'p - image border
    'q - image border width
    'r - image border color
    's - image filter
    't - watermark url
    'u - copyright text

    Friend ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return True
        End Get
    End Property

    Friend Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        Dim imgResponse As HttpResponse = context.Response
        Dim imgPath As String = String.Empty
        Dim imgUrl As String = Crypto.Decrypt(context.Request.QueryString("a"))
        Dim thumbWidth As Integer = context.Request.QueryString("b")
        Dim thumbHeight As Integer = context.Request.QueryString("c")
        Dim thumbQuality As Integer = context.Request.QueryString("d")
        Dim thumbBackgroundColor As Color = ColorTranslator.FromHtml(context.Server.UrlDecode(context.Request.QueryString("e")))

        'Get image object depending on source type.
        Dim img As Drawing.Image = Nothing

        'Read image.
        If imgUrl.StartsWith("http://") Or imgUrl.StartsWith("https://") Then
            img = Helpers.GetImageFromUrl(imgUrl)
        Else
            'Check if file exists.
            imgPath = context.Server.MapPath(imgUrl)
            If IO.File.Exists(imgPath) And Helpers.IsValidWebImage(imgPath) Then
                img = Drawing.Image.FromFile(imgPath)
            End If
        End If

        If img Is Nothing Then img = My.Resources.ImageError

        'Work on image.
        Dim bmp As Bitmap
        Dim srcWidth As Integer = img.Width
        Dim srcHeight As Integer = img.Height
        Dim srcX As Integer = 0
        Dim srcY As Integer = 0
        Dim destWidth As Integer = 0
        Dim destHeight As Integer = 0
        Dim destX As Integer = 0
        Dim destY As Integer = 0
        Dim resizeRatio As Single = 0
        Dim resizeRatioWidth As Single = 0
        Dim resizeRatioHeight As Single = 0

        'Calculate thumb width and height if both width and height are not given.
        If thumbWidth > 0 And thumbHeight = 0 Then
            thumbHeight = srcHeight * (thumbWidth / srcWidth)
        ElseIf thumbWidth = 0 And thumbHeight > 0 Then
            thumbWidth = srcWidth * (thumbHeight / srcHeight)
        End If

        'Calculate resize ratio.
        resizeRatioWidth = CSng(thumbWidth) / CSng(srcWidth)
        resizeRatioHeight = CSng(thumbHeight) / CSng(srcHeight)

        If resizeRatioHeight < resizeRatioWidth Then
            resizeRatio = resizeRatioWidth
            destY = CInt((thumbHeight - (srcHeight * resizeRatio)) / 2)
        Else
            resizeRatio = resizeRatioHeight
            destX = CInt((thumbWidth - (srcWidth * resizeRatio)) / 2)
        End If

        'Calculate destination size.
        destWidth = CInt(srcWidth * resizeRatio)
        destHeight = CInt(srcHeight * resizeRatio)

        'Create new bitmap.
        bmp = New Bitmap(thumbWidth, thumbHeight)

        'Draw image.
        Dim canvas As Graphics = Graphics.FromImage(bmp)
        Dim filter As Options.ImageFilters = Options.ImageFilters.None
        Dim destRectangle As New Rectangle(destX, destY, destWidth, destHeight)
        Dim srcRectangle As New Rectangle(srcX, srcY, srcWidth, srcHeight)

        'Set filter.
        If context.Request.QueryString("s") IsNot Nothing Then
            filter = context.Request.QueryString("s")
        End If

        canvas.SmoothingMode = SmoothingMode.HighQuality
        canvas.InterpolationMode = InterpolationMode.HighQualityBicubic
        canvas.PixelOffsetMode = PixelOffsetMode.HighQuality

        If filter = Options.ImageFilters.None Then
            canvas.DrawImage(img, destRectangle, srcRectangle, GraphicsUnit.Pixel)
        ElseIf filter = Options.ImageFilters.BlackAndWhite Then
            canvas.DrawImage(img, destRectangle, srcRectangle, GraphicsUnit.Pixel)
            Helpers.ConvertToBlackAndWhite(bmp)
        Else
            canvas.DrawImage(img, destRectangle, srcX, srcY, srcWidth, srcHeight, GraphicsUnit.Pixel, Helpers.GetImageFilter(filter))
        End If

        'Dispose image object.
        img.Dispose()

        'Draw border.
        Dim imageBorder As Pen = Nothing
        If context.Request.QueryString("p") IsNot Nothing Then
            Dim imageBorderColor As Color = ColorTranslator.FromHtml(context.Server.UrlDecode(context.Request.QueryString("r")))
            Dim imageBorderWidth As Integer = CInt(context.Request.QueryString("q"))
            imageBorder = New Pen(imageBorderColor, imageBorderWidth)
            imageBorder.DashStyle = CType(context.Request.QueryString("p"), DashStyle)
            imageBorder.Alignment = PenAlignment.Inset
            canvas.DrawRectangle(imageBorder, New Rectangle(0, 0, thumbWidth, thumbHeight))
        End If

        'Draw corners.
        Dim copyrightCornerRadius As Integer = 0
        If context.Request.QueryString("f") IsNot Nothing Then
            Dim cornerType As Integer = context.Request.QueryString("f")
            Dim cornerRadius As Integer = context.Request.QueryString("g")
            Dim topLeftCornerType As Integer = cornerType
            Dim topRightCornerType As Integer = cornerType
            Dim bottomRightCornerType As Integer = cornerType
            Dim bottomLeftCornerType As Integer = cornerType
            Dim topLeftCornerRadius As Integer = cornerRadius
            Dim topRightCornerRadius As Integer = cornerRadius
            Dim bottomRightCornerRadius As Integer = cornerRadius
            Dim bottomLeftCornerRadius As Integer = cornerRadius

            copyrightCornerRadius = bottomRightCornerRadius

            If context.Request.QueryString("h") IsNot Nothing Then topLeftCornerType = context.Request.QueryString("h")
            If context.Request.QueryString("i") IsNot Nothing Then topRightCornerType = context.Request.QueryString("i")
            If context.Request.QueryString("j") IsNot Nothing Then bottomRightCornerType = context.Request.QueryString("j")
            If context.Request.QueryString("k") IsNot Nothing Then bottomLeftCornerType = context.Request.QueryString("k")
            If context.Request.QueryString("l") IsNot Nothing Then topLeftCornerRadius = context.Request.QueryString("l")
            If context.Request.QueryString("m") IsNot Nothing Then topRightCornerRadius = context.Request.QueryString("m")
            If context.Request.QueryString("n") IsNot Nothing Then bottomRightCornerRadius = context.Request.QueryString("n")
            If context.Request.QueryString("o") IsNot Nothing Then bottomLeftCornerRadius = context.Request.QueryString("o")

            Helpers.DrawCorner(Options.Corners.TopLeft, topLeftCornerType, canvas, thumbBackgroundColor, thumbWidth, thumbHeight, topLeftCornerRadius, imageBorder)
            Helpers.DrawCorner(Options.Corners.TopRight, topRightCornerType, canvas, thumbBackgroundColor, thumbWidth, thumbHeight, topRightCornerRadius, imageBorder)
            Helpers.DrawCorner(Options.Corners.BottomRight, bottomRightCornerType, canvas, thumbBackgroundColor, thumbWidth, thumbHeight, bottomRightCornerRadius, imageBorder)
            Helpers.DrawCorner(Options.Corners.BottomLeft, bottomLeftCornerType, canvas, thumbBackgroundColor, thumbWidth, thumbHeight, bottomLeftCornerRadius, imageBorder)
        End If

        'Draw watermark.
        If context.Request.QueryString("t") IsNot Nothing Then
            Dim watermarkImageUrl As String = Crypto.Decrypt(context.Request.QueryString("t"))
            Dim watermark As Drawing.Image = Nothing

            If watermarkImageUrl.StartsWith("http://") Or watermarkImageUrl.StartsWith("https://") Then
                watermark = Helpers.GetImageFromUrl(watermarkImageUrl)
            Else
                watermarkImageUrl = context.Server.MapPath(watermarkImageUrl)
                If IO.File.Exists(watermarkImageUrl) And Helpers.IsValidWebImage(watermarkImageUrl) Then
                    watermark = Drawing.Image.FromFile(watermarkImageUrl)
                End If
            End If

            If watermark IsNot Nothing Then
                Dim watermarkWidth As Single = watermark.Width
                Dim watermarkHeight As Single = watermark.Height
                Dim watermarkDiffW As Single = watermarkWidth - CSng(thumbWidth)
                Dim watermarkDiffH As Single = watermarkHeight - CSng(thumbHeight)
                Dim watermarkRatio As Single = 1

                If watermarkDiffW > 0 Or watermarkDiffH > 0 Then
                    If watermarkDiffW > watermarkDiffH Then
                        watermarkRatio = CSng(thumbWidth) / watermarkWidth
                    Else
                        watermarkRatio = CSng(thumbHeight) / watermarkHeight
                    End If
                    watermarkWidth = watermarkWidth * watermarkRatio
                    watermarkHeight = watermarkHeight * watermarkRatio
                End If

                canvas.DrawImage(watermark, New RectangleF((thumbWidth / 2) - (watermarkWidth / 2), (thumbHeight / 2) - (watermarkHeight / 2), watermarkWidth, watermarkHeight))
                watermark.Dispose()
            End If
        End If

        'Draw copyright.
        If context.Request.QueryString("u") IsNot Nothing Then
            Dim copyrightTextBrush As New SolidBrush(Color.White)
            Dim copyrightBackBrush As New SolidBrush(Color.Black)
            Dim copyrightText As String = context.Server.UrlDecode(context.Request.QueryString("u"))
            Dim copyrightFont As New Font("Tahoma", 10, FontStyle.Regular, GraphicsUnit.Pixel)
            Dim copyrightTextSize As SizeF = canvas.MeasureString(copyrightText, copyrightFont)

            Dim copyrightBorderAdd As Integer = 0
            If imageBorder IsNot Nothing Then copyrightBorderAdd = imageBorder.Width - 1

            Dim copyrightRect As New RectangleF(thumbWidth - copyrightTextSize.Width - copyrightCornerRadius, thumbHeight - copyrightTextSize.Height - copyrightBorderAdd, copyrightTextSize.Width, copyrightTextSize.Height)
            canvas.FillRectangle(copyrightBackBrush, copyrightRect)
            canvas.DrawString(copyrightText, copyrightFont, copyrightTextBrush, copyrightRect)
        End If

        'Write image to response stream.
        Dim stream As MemoryStream = New MemoryStream
        Dim mimeType As String = Helpers.GetImageMimeType(imgPath)
        imgResponse.ContentType = mimeType

        If mimeType = "image/png" Then
            'PNG has no quality parameter.
            bmp.Save(stream, ImageFormat.Png)
        Else
            'Set image quality.
            Dim encodeParams As EncoderParameters = New EncoderParameters(1)
            encodeParams.Param(0) = New EncoderParameter(Imaging.Encoder.Quality, thumbQuality)
            bmp.Save(stream, Helpers.GetImageCodecInfo(mimeType), encodeParams)
        End If

        imgResponse.Buffer = True
        imgResponse.Expires = 60
        stream.WriteTo(imgResponse.OutputStream)
        stream.Dispose()
    End Sub

End Class
